﻿package com.crl.module.logging.targets
{
    import com.crl.module.logging.ILogger;
    import com.crl.module.logging.ILoggerTarget;
    import com.crl.module.logging.LoggerFactory;
    import com.crl.module.logging.LoggerLevel;
    import com.crl.module.logging.LoggerStrings;
    import com.crl.module.logging.events.LoggerEvent;
    import com.crl.utils.StringUtil;
    
    import flash.errors.IllegalOperationError;
    import flash.events.EventDispatcher;
    
 
    public class CoreLoggerTarget extends EventDispatcher implements ILoggerTarget
    {
        public function CoreLoggerTarget()
        {
            _factory = Log;
            _filters =  ["*"];
            _level   = LoggerLevel.ALL;
        }
		
        public function get factory():LoggerFactory
        {
            return _factory ;
        }

        public function set factory( factory:LoggerFactory ):void
        {
            if ( _factory != null )
            {
                _factory.removeTarget( this ) ;
            }
            _factory = factory;
            _factory.addTarget( this ) ;
        }
        
        /**
         * Indicates the filters array representation of this target.
         */
        public function get filters():Array
        {
            return _filters;
        }
        
        /**
         * @private
         */
        public function set filters( value:Array ):void
        {
            if ( value == null || value.length< 1 ){
                value = ["*"] ;
            }
            
            if ( _count > 0 )
            {
                _factory.removeTarget( this ) ;
            }
            
            _filters = value.concat() ;
            if ( _count > 0 )
            {
                _factory.addTarget( this ) ;
            }
        }
        
        /**
         * Indicates the level of this target.
         */
        public function get level():LoggerLevel
        {
            return _level ;
        }
        
        /**
         * @private
         */
        public function set level( value:LoggerLevel ):void
        {
            _factory.removeTarget( this ) ;
            _level = value || LoggerLevel.ALL ;
            _factory.addTarget( this ) ;
        } 
        
        /**
         * Insert a channel in the fllters if this channel don't exist.
         * Returns a boolean if the channel is add in the list.
         */
        public function addFilter( channel:String ):Boolean 
        {
            _checkFilter( channel ) ;
            return _filters.add( channel ) ;
        }
        
        /**
         * Sets up this target with the specified logger.
         * Note : this method is called by the framework and should not be called by the developer.
         */
        public function addLogger( logger:ILogger ):void 
        {
            if ( logger != null )
            {
                _count++ ;
                logger.addEventListener( LoggerEvent.LOG , _handleEvent ) ;
            }
        }
        
        /**
         *  This method handles a <code class="prettyprint">LoggerEvent</code> from an associated logger.
         *  A target uses this method to translate the event into the appropriate format for transmission, storage, or display.
         *  This method will be called only if the event's level is in range of the target's level.
         *  <b><i>Descendants need to override this method to make it useful.</i></b>
         */
        public function logEvent( event:LoggerEvent ):void
        {
            // override please.
        }
        
        /**
         * Remove a channel in the fllters if this channel exist.
         * @return a boolean if the channel is removed.
         */
        public function removeFilter( channel:String ):Boolean
        {
			var index:int=_filters.indexOf(channel);
			if(index==-1)return false;
			
			_filters.splice(index,1);
            return true;
        }
        
        /**
         * Stops this target from receiving events from the specified logger.
         */
        public function removeLogger( logger:Logger ):void 
        {
            if ( logger != null )
            {
                _count-- ;
                logger.removeEventListener( LoggerEvent.LOG , _handleEvent ) ;
            }
        }
        
        /**
         * Count of the number of loggers this target is listening to. 
         * When this value is zero changes to the filters property shouldn't do anything.
         * @private
         */
        private var _count:uint ;
        
        /**
         * @private
         */
        private var _factory:LoggerFactory;
        
        /**
         * @private
         */
        private var _filters:Array;
        
        /**
         * @private
         */
        private var _level:LoggerLevel;
        
        /**
         * @private
         */
        private function _checkFilter( filter:String ):void
        {
            if ( filter == null )
            {
                throw new IllegalOperationError( LoggerStrings.EMPTY_FILTER  ) ;
            }
            
            if ( _factory.hasIllegalCharacters(filter) )
            {
                 throw new IllegalOperationError( StringUtil.substitute( LoggerStrings.ERROR_FILTER , filter ) + LoggerStrings.CHARS_INVALID ) ;
            }
            
            var index:int = filter.indexOf("*") ;
            if ((index >= 0) && (index != (filter.length -1)))
            {
                throw new IllegalOperationError( StringUtil.substitute( LoggerStrings.ERROR_FILTER , filter) + LoggerStrings.CHAR_PLACEMENT ) ;
            }
        }
        
        /**
         * This method will call the <code class="prettyprint">logEvent</code> method if the level of the event is appropriate for the current level.
         */
        private function _handleEvent( event:LoggerEvent ):void
        {
            if ( _level == LoggerLevel.NONE )
            {
                return ; // logging off
            }
            else if ( int( event.level ) >= int( _level ) )
            {
                logEvent(event) ;
            }
        }
    }
}